home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sndhrdw / galaxian.c < prev    next >
C/C++ Source or Header  |  2000-05-04  |  17KB  |  683 lines

  1. #include "driver.h"
  2. #include <math.h>
  3.  
  4. #define VERBOSE 0
  5.  
  6. #define NEW_LFO 0
  7. #define NEW_SHOOT 1
  8.  
  9. #define XTAL        18432000
  10.  
  11. #define SOUND_CLOCK (XTAL/6/2)            /* 1.536 Mhz */
  12.  
  13. #define SAMPLES 1
  14.  
  15. #define RNG_RATE    (XTAL/3)            /* RNG clock is XTAL/3 */
  16. #define NOISE_RATE    (XTAL/3/192/2/2)    /* 2V = 8kHz */
  17. #define NOISE_LENGTH (NOISE_RATE*4)     /* four seconds of noise */
  18.  
  19. #define SHOOT_RATE 2672
  20. #define SHOOT_LENGTH 13000
  21.  
  22. #define TOOTHSAW_LENGTH 16
  23. #define TOOTHSAW_VOLUME 36
  24. #define STEPS 16
  25. #define LFO_VOLUME 6
  26. #define SHOOT_VOLUME 50
  27. #define NOISE_VOLUME 50
  28. #define NOISE_AMPLITUDE 70*256
  29. #define TOOTHSAW_AMPLITUDE 64
  30.  
  31. /* see comments in galaxian_sh_update() */
  32. #define MINFREQ (139-139/3)
  33. #define MAXFREQ (139+139/3)
  34.  
  35. #if VERBOSE
  36. #define LOG(x) logerror x
  37. #else
  38. #define LOG(x)
  39. #endif
  40.  
  41. static void *lfotimer = 0;
  42. static int freq = MAXFREQ;
  43.  
  44. #define STEP 1
  45.  
  46. static void *noisetimer = 0;
  47. static int noisevolume;
  48. static INT16 *noisewave;
  49. static INT16 *shootwave;
  50. #if NEW_SHOOT
  51. static int shoot_length;
  52. static int shoot_rate;
  53. #endif
  54.  
  55. #if SAMPLES
  56. static int shootsampleloaded = 0;
  57. static int deathsampleloaded = 0;
  58. static int last_port1=0;
  59. #endif
  60. static int last_port2=0;
  61.  
  62. static INT8 tonewave[4][TOOTHSAW_LENGTH];
  63. static int pitch,vol;
  64.  
  65. static INT16 backgroundwave[32] =
  66. {
  67.    0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000,
  68.    0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000,
  69.   -0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,
  70.   -0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,
  71. };
  72.  
  73. static int channelnoise,channelshoot,channellfo;
  74. static int tone_stream;
  75.  
  76. static void tone_update(int ch, INT16 *buffer, int length)
  77. {
  78.     int i,j;
  79.     INT8 *w = tonewave[vol];
  80.     static int counter, countdown;
  81.  
  82.     /* only update if we have non-zero volume and frequency */
  83.     if( pitch != 0xff )
  84.     {
  85.         for (i = 0; i < length; i++)
  86.         {
  87.             int mix = 0;
  88.  
  89.             for (j = 0;j < STEPS;j++)
  90.             {
  91.                 if (countdown >= 256)
  92.                 {
  93.                     counter = (counter + 1) % TOOTHSAW_LENGTH;
  94.                     countdown = pitch;
  95.                 }
  96.                 countdown++;
  97.  
  98.                 mix += w[counter];
  99.             }
  100.             *buffer++ = (mix << 8) / STEPS;
  101.         }
  102.     }
  103.     else
  104.     {
  105.         for( i = 0; i < length; i++ )
  106.             *buffer++ = 0;
  107.     }
  108. }
  109.  
  110. WRITE_HANDLER( galaxian_pitch_w )
  111. {
  112.     stream_update(tone_stream,0);
  113.  
  114.     pitch = data;
  115. }
  116.  
  117. WRITE_HANDLER( galaxian_vol_w )
  118. {
  119.     stream_update(tone_stream,0);
  120.  
  121.     /* offset 0 = bit 0, offset 1 = bit 1 */
  122.     vol = (vol & ~(1 << offset)) | ((data & 1) << offset);
  123. }
  124.  
  125.  
  126. static void noise_timer_cb(int param)
  127. {
  128.     if( noisevolume > 0 )
  129.     {
  130.         noisevolume -= (noisevolume / 10) + 1;
  131.         mixer_set_volume(channelnoise,noisevolume);
  132.     }
  133. }
  134.  
  135. WRITE_HANDLER( galaxian_noise_enable_w )
  136. {
  137. #if SAMPLES
  138.     if (deathsampleloaded)
  139.     {
  140.         if (data & 1 && !(last_port1 & 1))
  141.             mixer_play_sample(channelnoise,Machine->samples->sample[1]->data,
  142.                     Machine->samples->sample[1]->length,
  143.                     Machine->samples->sample[1]->smpfreq,
  144.                     0);
  145.         last_port1=data;
  146.     }
  147.     else
  148. #endif
  149.     {
  150.         if( data & 1 )
  151.         {
  152.             if( noisetimer )
  153.             {
  154.                 timer_remove(noisetimer);
  155.                 noisetimer = 0;
  156.             }
  157.             noisevolume = 100;
  158.             mixer_set_volume(channelnoise,noisevolume);
  159.         }
  160.         else
  161.         {
  162.             /* discharge C21, 22uF via 150k+22k R35/R36 */
  163.             if (noisevolume == 100)
  164.             {
  165.                 noisetimer = timer_pulse(TIME_IN_USEC(0.693*(155000+22000)*22 / 100), 0, noise_timer_cb);
  166.             }
  167.         }
  168.     }
  169. }
  170.  
  171. WRITE_HANDLER( galaxian_shoot_enable_w )
  172. {
  173.     if( data & 1 && !(last_port2 & 1) )
  174.     {
  175. #if SAMPLES
  176.         if( shootsampleloaded )
  177.         {
  178.             mixer_play_sample(channelshoot,Machine->samples->sample[0]->data,
  179.                     Machine->samples->sample[0]->length,
  180.                     Machine->samples->sample[0]->smpfreq,
  181.                     0);
  182.         }
  183.         else
  184. #endif
  185.         {
  186. #if NEW_SHOOT
  187.             mixer_play_sample_16(channelshoot, shootwave, shoot_length, shoot_rate, 0);
  188. #else
  189.             mixer_play_sample_16(channelshoot, shootwave, SHOOT_LENGTH, 10*SHOOT_RATE, 0);
  190. #endif
  191.             mixer_set_volume(channelshoot,SHOOT_VOLUME);
  192.         }
  193.     }
  194.     last_port2=data;
  195. }
  196.  
  197.  
  198. #if SAMPLES
  199. static const char *galaxian_sample_names[] =
  200. {
  201.     "*galaxian",
  202.     "shot.wav",
  203.     "death.wav",
  204.     0    /* end of array */
  205. };
  206. #endif
  207.  
  208. int galaxian_sh_start(const struct MachineSound *msound)
  209. {
  210.     int i, j, sweep, charge, countdown, generator, bit1, bit2;
  211.     int lfovol[3] = {LFO_VOLUME,LFO_VOLUME,LFO_VOLUME};
  212.  
  213. #if SAMPLES
  214.     Machine->samples = readsamples(galaxian_sample_names,Machine->gamedrv->name);
  215. #endif
  216.  
  217.     channelnoise = mixer_allocate_channel(NOISE_VOLUME);
  218.     mixer_set_name(channelnoise,"Noise");
  219.     channelshoot = mixer_allocate_channel(SHOOT_VOLUME);
  220.     mixer_set_name(channelshoot,"Shoot");
  221.     channellfo = mixer_allocate_channels(3,lfovol);
  222.     mixer_set_name(channellfo+0,"Background #0");
  223.     mixer_set_name(channellfo+1,"Background #1");
  224.     mixer_set_name(channellfo+2,"Background #2");
  225.  
  226. #if SAMPLES
  227.     if (Machine->samples != 0 && Machine->samples->sample[0] != 0)    /* We should check also that Samplename[0] = 0 */
  228.         shootsampleloaded = 1;
  229.     else
  230.         shootsampleloaded = 0;
  231.  
  232.     if (Machine->samples != 0 && Machine->samples->sample[1] != 0)    /* We should check also that Samplename[0] = 0 */
  233.         deathsampleloaded = 1;
  234.     else
  235.         deathsampleloaded = 0;
  236. #endif
  237.  
  238.     if( (noisewave = malloc(NOISE_LENGTH * sizeof(INT16))) == 0 )
  239.     {
  240.         return 1;
  241.     }
  242.  
  243. #if NEW_SHOOT
  244. #define SHOOT_SEC 2
  245.     shoot_rate = Machine->sample_rate;
  246.     shoot_length = SHOOT_SEC * shoot_rate;
  247.     if ((shootwave = malloc(shoot_length * sizeof(INT16))) == 0)
  248. #else
  249.     if( (shootwave = malloc(SHOOT_LENGTH * sizeof(INT16))) == 0 )
  250. #endif
  251.     {
  252.         free(noisewave);
  253.         return 1;
  254.     }
  255.  
  256.     /*
  257.      * The RNG shifter is clocked with RNG_RATE, bit 17 is
  258.      * latched every 2V cycles (every 2nd scanline).
  259.      * This signal is used as a noise source.
  260.      */
  261.     generator = 0;
  262.     countdown = NOISE_RATE / 2;
  263.     for( i = 0; i < NOISE_LENGTH; i++ )
  264.     {
  265.         countdown -= RNG_RATE;
  266.         while( countdown < 0 )
  267.         {
  268.             generator <<= 1;
  269.             bit1 = (~generator >> 17) & 1;
  270.             bit2 = (generator >> 5) & 1;
  271.             if (bit1 ^ bit2) generator |= 1;
  272.             countdown += NOISE_RATE;
  273.         }
  274.         noisewave[i] = ((generator >> 17) & 1) ? NOISE_AMPLITUDE : -NOISE_AMPLITUDE;
  275.     }
  276.  
  277. #if NEW_SHOOT
  278.  
  279.     /* dummy */
  280.     sweep = 100;
  281.     charge = +2;
  282.     j=0;
  283.     {
  284. #define R41__ 100000
  285. #define R44__ 10000
  286. #define R45__ 22000
  287. #define R46__ 10000
  288. #define R47__ 2200
  289. #define R48__ 2200
  290. #define C25__ 0.000001
  291. #define C27__ 0.00000001
  292. #define C28__ 0.000047
  293. #define C29__ 0.00000001
  294. #define IC8L3_L 0.2   /* 7400 L level */
  295. #define IC8L3_H 4.5   /* 7400 H level */
  296. #define NOISE_L 0.2   /* 7474 L level */
  297. #define NOISE_H 4.5   /* 7474 H level */
  298. /*
  299.     key on/off time is programmable
  300.     Therefore,  it is necessary to make separate sample with key on/off.
  301.     And,  calculate the playback point according to the voltage of c28.
  302. */
  303. #define SHOOT_KEYON_TIME 0.1  /* second */
  304. /*
  305.     NE555-FM input calculation is wrong.
  306.     The frequency is not proportional to the voltage of FM input.
  307.     And,  duty will be changed,too.
  308. */
  309. #define NE555_FM_ADJUST_RATE 0.80
  310.         /* discharge : 100K * 1uF */
  311.         double v  = 5.0;
  312.         double vK = (shoot_rate) ? exp(-1 / (R41__*C25__) / shoot_rate) : 0;
  313.         /* -- SHOOT KEY port -- */
  314.         double IC8L3 = IC8L3_L; /* key on */
  315.         int IC8Lcnt = SHOOT_KEYON_TIME * shoot_rate; /* count for key off */
  316.         /* C28 : KEY port capacity */
  317.         /*       connection : 8L-3 - R47(2.2K) - C28(47u) - R48(2.2K) - C29 */
  318.         double c28v = IC8L3_H - (IC8L3_H-(NOISE_H+NOISE_L)/2)/(R46__+R47__+R48__)*R47__;
  319.         double c28K = (shoot_rate) ? exp(-1 / (22000 * 0.000047 ) / shoot_rate) : 0;
  320.         /* C29 : NOISE capacity */
  321.         /*       connection : NOISE - R46(10K) - C29(0.1u) - R48(2.2K) - C28 */
  322.         double c29v  = IC8L3_H - (IC8L3_H-(NOISE_H+NOISE_L)/2)/(R46__+R47__+R48__)*(R47__+R48__);
  323.         double c29K1 = (shoot_rate) ? exp(-1 / (22000  * 0.00000001 ) / shoot_rate) : 0; /* form C28   */
  324.         double c29K2 = (shoot_rate) ? exp(-1 / (100000 * 0.00000001 ) / shoot_rate) : 0; /* from noise */
  325.         /* NE555 timer */
  326.         /* RA = 10K , RB = 22K , C=.01u ,FM = C29 */
  327.         double ne555cnt = 0;
  328.         double ne555step = (shoot_rate) ? ((1.44/((R44__+R45__*2)*C27__)) / shoot_rate) : 0;
  329.         double ne555duty = (double)(R44__+R45__)/(R44__+R45__*2); /* t1 duty */
  330.         double ne555sr;        /* threshold (FM) rate */
  331.         /* NOISE source */
  332.         double ncnt  = 0.0;
  333.         double nstep = (shoot_rate) ? ((double)NOISE_RATE / shoot_rate) : 0;
  334.         double noise_sh2; /* voltage level */
  335.  
  336.         for( i = 0; i < shoot_length; i++ )
  337.         {
  338.             /* noise port */
  339.             noise_sh2 = noisewave[(int)ncnt % NOISE_LENGTH] == NOISE_AMPLITUDE ? NOISE_H : NOISE_L;
  340.             ncnt+=nstep;
  341.             /* calculate NE555 threshold level by FM input */
  342.             ne555sr = c29v*NE555_FM_ADJUST_RATE / (5.0*2/3);
  343.             /* calc output */
  344.             ne555cnt += ne555step;
  345.             if( ne555cnt >= ne555sr) ne555cnt -= ne555sr;
  346.             if( ne555cnt < ne555sr*ne555duty )
  347.             {
  348.                  /* t1 time */
  349.                 shootwave[i] = v/5*0x7fff;
  350.                 /* discharge output level */
  351.                 if(IC8L3==IC8L3_H)
  352.                     v *= vK;
  353.             }
  354.             else
  355.                 shootwave[i] = 0;
  356.             /* C28 charge/discharge */
  357.             c28v += (IC8L3-c28v) - (IC8L3-c28v)*c28K;    /* from R47 */
  358.             c28v += (c29v-c28v) - (c29v-c28v)*c28K;        /* from R48 */
  359.             /* C29 charge/discharge */
  360.             c29v += (c28v-c29v) - (c28v-c29v)*c29K1;    /* from R48 */
  361.             c29v += (noise_sh2-c29v) - (noise_sh2-c29v)*c29K2;    /* from R46 */
  362.             /* key off */
  363.             if(IC8L3==IC8L3_L && --IC8Lcnt==0)
  364.                 IC8L3=IC8L3_H;
  365.         }
  366.     }
  367. #else
  368.     /*
  369.      * Ra is 10k, Rb is 22k, C is 0.01uF
  370.      * charge time t1 = 0.693 * (Ra + Rb) * C -> 221.76us
  371.      * discharge time t2 = 0.693 * (Rb) *  C -> 152.46us
  372.      * average period 374.22us -> 2672Hz
  373.      * I use an array of 10 values to define some points
  374.      * of the charge/discharge curve. The wave is modulated
  375.      * using the charge/discharge timing of C28, a 47uF capacitor,
  376.      * over a 2k2 resistor. This will change the frequency from
  377.      * approx. Favg-Favg/3 up to Favg+Favg/3 down to Favg-Favg/3 again.
  378.      */
  379.     sweep = 100;
  380.     charge = +2;
  381.     countdown = sweep / 2;
  382.     for( i = 0, j = 0; i < SHOOT_LENGTH; i++ )
  383.     {
  384.         #define AMP(n)    (n)*0x8000/100-0x8000
  385.         static int charge_discharge[10] = {
  386.             AMP( 0), AMP(25), AMP(45), AMP(60), AMP(70), AMP(85),
  387.             AMP(70), AMP(50), AMP(25), AMP( 0)
  388.         };
  389.         shootwave[i] = charge_discharge[j];
  390.         LOG(("shoot[%5d] $%04x (sweep: %3d, j:%d)\n", i, shootwave[i] & 0xffff, sweep, j));
  391.         /*
  392.          * The current sweep and a 2200/10000 fraction (R45 and R48)
  393.          * of the noise are frequency modulating the NE555 chip.
  394.          */
  395.         countdown -= sweep + noisewave[i % NOISE_LENGTH] / (2200*NOISE_AMPLITUDE/10000);
  396.         while( countdown < 0 )
  397.         {
  398.             countdown += 100;
  399.             j = ++j % 10;
  400.         }
  401.         /* sweep from 100 to 133 and down to 66 over the time of SHOOT_LENGTH */
  402.         if( i % (SHOOT_LENGTH / 33 / 3 ) == 0 )
  403.         {
  404.             sweep += charge;
  405.             if( sweep >= 133 )
  406.                 charge = -1;
  407.         }
  408.     }
  409. #endif
  410.  
  411.     memset(tonewave, 0, sizeof(tonewave));
  412.  
  413.     for( i = 0; i < TOOTHSAW_LENGTH; i++ )
  414.     {
  415.         #define V(r0,r1) 2*TOOTHSAW_AMPLITUDE*(r0)/(r0+r1)-TOOTHSAW_AMPLITUDE
  416.         double r0a = 1.0/1e12, r1a = 1.0/1e12;
  417.         double r0b = 1.0/1e12, r1b = 1.0/1e12;
  418.  
  419.         /* #0: VOL1=0 and VOL2=0
  420.          * only the 33k and the 22k resistors R51 and R50
  421.          */
  422.         if( i & 1 )
  423.         {
  424.             r1a += 1.0/33000;
  425.             r1b += 1.0/33000;
  426.         }
  427.         else
  428.         {
  429.             r0a += 1.0/33000;
  430.             r0b += 1.0/33000;
  431.         }
  432.         if( i & 4 )
  433.         {
  434.             r1a += 1.0/22000;
  435.             r1b += 1.0/22000;
  436.         }
  437.         else
  438.         {
  439.             r0a += 1.0/22000;
  440.             r0b += 1.0/22000;
  441.         }
  442.         tonewave[0][i] = V(1.0/r0a, 1.0/r1a);
  443.  
  444.         /* #1: VOL1=1 and VOL2=0
  445.          * add the 10k resistor R49 for bit QC
  446.          */
  447.         if( i & 4 )
  448.             r1a += 1.0/10000;
  449.         else
  450.             r0a += 1.0/10000;
  451.         tonewave[1][i] = V(1.0/r0a, 1.0/r1a);
  452.  
  453.         /* #2: VOL1=0 and VOL2=1
  454.          * add the 15k resistor R52 for bit QD
  455.          */
  456.         if( i & 8 )
  457.             r1b += 1.0/15000;
  458.         else
  459.             r0b += 1.0/15000;
  460.         tonewave[2][i] = V(1.0/r0b, 1.0/r1b);
  461.  
  462.         /* #3: VOL1=1 and VOL2=1
  463.          * add the 10k resistor R49 for QC
  464.          */
  465.         if( i & 4 )
  466.             r0b += 1.0/10000;
  467.         else
  468.             r1b += 1.0/10000;
  469.         tonewave[3][i] = V(1.0/r0b, 1.0/r1b);
  470.         LOG(("tone[%2d]: $%02x $%02x $%02x $%02x\n", i, tonewave[0][i], tonewave[1][i], tonewave[2][i], tonewave[3][i]));
  471.     }
  472.  
  473.     pitch = 0;
  474.     vol = 0;
  475.  
  476.     tone_stream = stream_init("Tone",TOOTHSAW_VOLUME,SOUND_CLOCK/STEPS,0,tone_update);
  477.  
  478. #if SAMPLES
  479.     if (!deathsampleloaded)
  480. #endif
  481.     {
  482.         mixer_set_volume(channelnoise,0);
  483.         mixer_play_sample_16(channelnoise,noisewave,NOISE_LENGTH,NOISE_RATE,1);
  484.     }
  485. #if SAMPLES
  486.     if (!shootsampleloaded)
  487. #endif
  488.     {
  489.         mixer_set_volume(channelshoot,0);
  490.         mixer_play_sample_16(channelshoot,shootwave,SHOOT_LENGTH,SHOOT_RATE,1);
  491.     }
  492.  
  493.     mixer_set_volume(channellfo+0,0);
  494.     mixer_play_sample_16(channellfo+0,backgroundwave,sizeof(backgroundwave),1000,1);
  495.     mixer_set_volume(channellfo+1,0);
  496.     mixer_play_sample_16(channellfo+1,backgroundwave,sizeof(backgroundwave),1000,1);
  497.     mixer_set_volume(channellfo+2,0);
  498.     mixer_play_sample_16(channellfo+2,backgroundwave,sizeof(backgroundwave),1000,1);
  499.  
  500.     return 0;
  501. }
  502.  
  503.  
  504.  
  505. void galaxian_sh_stop(void)
  506. {
  507.     if( lfotimer )
  508.     {
  509.         timer_remove( lfotimer );
  510.         lfotimer = 0;
  511.     }
  512.     if( noisetimer )
  513.     {
  514.         timer_remove(noisetimer);
  515.         noisetimer = 0;
  516.     }
  517.     mixer_stop_sample(channelnoise);
  518.     mixer_stop_sample(channelshoot);
  519.     mixer_stop_sample(channellfo+0);
  520.     mixer_stop_sample(channellfo+1);
  521.     mixer_stop_sample(channellfo+2);
  522.     free(noisewave);
  523.     noisewave = 0;
  524.     free(shootwave);
  525.     shootwave = 0;
  526. }
  527.  
  528. WRITE_HANDLER( galaxian_background_enable_w )
  529. {
  530.     mixer_set_volume(channellfo+offset,(data & 1) ? 100 : 0);
  531. }
  532.  
  533. static void lfo_timer_cb(int param)
  534. {
  535.     if( freq > MINFREQ )
  536.         freq--;
  537.     else
  538.         freq = MAXFREQ;
  539. }
  540.  
  541. WRITE_HANDLER( galaxian_lfo_freq_w )
  542. {
  543. #if NEW_LFO
  544.     static int lfobit[4];
  545.  
  546.     /* R18 1M,R17 470K,R16 220K,R15 100K */
  547.     const int rv[4] = { 1000000,470000,220000,100000};
  548.     double r1,r2,Re,td;
  549.     int i;
  550.  
  551.     if( (data & 1) == lfobit[offset] )
  552.         return;
  553.  
  554.     /*
  555.      * NE555 9R is setup as astable multivibrator
  556.      * - this circuit looks LINEAR RAMP V-F converter
  557.        I  = 1/Re * ( R1/(R1+R2)-Vbe)
  558.        td = (2/3VCC*Re*(R1+R2)*C) / (R1*VCC-Vbe*(R1+R2))
  559.       parts assign
  560.        R1  : (R15* L1)|(R16* L2)|(R17* L3)|(R18* L1)
  561.        R2  : (R15*~L1)|(R16*~L2)|(R17*~L3)|(R18*~L4)|R??(330K)
  562.        Re  : R21(100K)
  563.        Vbe : Q2(2SA1015)-Vbe
  564.      * - R20(15K) and Q1 is unknown,maybe current booster.
  565.     */
  566.  
  567.     lfobit[offset] = data & 1;
  568.  
  569.     /* R20 15K */
  570.     r1 = 1e12;
  571.     /* R19? 330k to gnd */
  572.     r2 = 330000;
  573.     //r1 = 15000;
  574.     /* R21 100K */
  575.     Re = 100000;
  576.     /* register calculation */
  577.     for(i=0;i<4;i++)
  578.     {
  579.         if(lfobit[i])
  580.             r1 = (r1*rv[i])/(r1+rv[i]); /* Hi  */
  581.         else
  582.             r2 = (r2*rv[i])/(r2+rv[i]); /* Low */
  583.     }
  584.  
  585.     if( lfotimer )
  586.     {
  587.         timer_remove( lfotimer );
  588.         lfotimer = 0;
  589.     }
  590.  
  591. #define Vcc 5.0
  592. #define Vbe 0.65        /* 2SA1015 */
  593. #define Cap 0.000001    /* C15 1uF */
  594.     td = (Vcc*2/3*Re*(r1+r2)*Cap) / (r1*Vcc - Vbe*(r1+r2) );
  595. #undef Cap
  596. #undef Vbe
  597. #undef Vcc
  598.     logerror("lfo timer bits:%d%d%d%d r1:%d, r2:%d, re: %d, td: %9.2fsec\n", lfobit[0], lfobit[1], lfobit[2], lfobit[3], (int)r1, (int)r2, (int)Re, td);
  599.     lfotimer = timer_pulse( TIME_IN_SEC(td / (MAXFREQ-MINFREQ)), 0, lfo_timer_cb);
  600. #else
  601.     static int lfobit[4];
  602.     double r0, r1, rx = 100000.0;
  603.  
  604.     if( (data & 1) == lfobit[offset] )
  605.         return;
  606.  
  607.     /*
  608.      * NE555 9R is setup as astable multivibrator
  609.      * - Ra is between 100k and ??? (open?)
  610.      * - Rb is zero here (bridge between pins 6 and 7)
  611.      * - C is 1uF
  612.      * charge time t1 = 0.693 * (Ra + Rb) * C
  613.      * discharge time t2 = 0.693 * (Rb) *  C
  614.      * period T = t1 + t2 = 0.693 * (Ra + 2 * Rb) * C
  615.      * -> min period: 0.693 * 100 kOhm * 1uF -> 69300 us = 14.4Hz
  616.      * -> max period: no idea, since I don't know the max. value for Ra :(
  617.      */
  618.  
  619.     lfobit[offset] = data & 1;
  620.  
  621.     /* R?? 330k to gnd */
  622.     r0 = 1.0/330000;
  623.     /* open is a very high value really ;-) */
  624.     r1 = 1.0/1e12;
  625.  
  626.     /* R18 1M */
  627.     if( lfobit[0] )
  628.         r1 += 1.0/1000000;
  629.     else
  630.         r0 += 1.0/1000000;
  631.  
  632.     /* R17 470k */
  633.     if( lfobit[1] )
  634.         r1 += 1.0/470000;
  635.     else
  636.         r0 += 1.0/470000;
  637.  
  638.     /* R16 220k */
  639.     if( lfobit[2] )
  640.         r1 += 1.0/220000;
  641.     else
  642.         r0 += 1.0/220000;
  643.  
  644.     /* R15 100k */
  645.     if( lfobit[3] )
  646.         r1 += 1.0/100000;
  647.     else
  648.         r0 += 1.0/100000;
  649.  
  650.     if( lfotimer )
  651.     {
  652.         timer_remove( lfotimer );
  653.         lfotimer = 0;
  654.     }
  655.  
  656.     r0 = 1.0/r0;
  657.     r1 = 1.0/r1;
  658.  
  659.     /* I used an arbitrary value for max. Ra of 2M */
  660.     rx = rx + 2000000.0 * r0 / (r0+r1);
  661.  
  662.     LOG(("lfotimer bits:%d%d%d%d r0:%d, r1:%d, rx: %d, time: %9.2fus\n", lfobit[3], lfobit[2], lfobit[1], lfobit[0], (int)r0, (int)r1, (int)rx, 0.639 * rx));
  663.     lfotimer = timer_pulse( TIME_IN_USEC(0.639 * rx / (MAXFREQ-MINFREQ)), 0, lfo_timer_cb);
  664. #endif
  665. }
  666.  
  667. void galaxian_sh_update(void)
  668. {
  669.     /*
  670.      * NE555 8R, 8S and 8T are used as pulse position modulators
  671.      * FS1 Ra=100k, Rb=470k and C=0.01uF
  672.      *    -> 0.693 * 1040k * 0.01uF -> 7207.2us = 139Hz
  673.      * FS2 Ra=100k, Rb=330k and C=0.01uF
  674.      *    -> 0.693 * 760k * 0.01uF -> 5266.8us = 190Hz
  675.      * FS2 Ra=100k, Rb=220k and C=0.01uF
  676.      *    -> 0.693 * 540k * 0.01uF -> 3742.2us = 267Hz
  677.      */
  678.  
  679.     mixer_set_sample_frequency(channellfo+0, sizeof(backgroundwave)*freq*(100+2*470)/(100+2*470) );
  680.     mixer_set_sample_frequency(channellfo+1, sizeof(backgroundwave)*freq*(100+2*300)/(100+2*470) );
  681.     mixer_set_sample_frequency(channellfo+2, sizeof(backgroundwave)*freq*(100+2*220)/(100+2*470) );
  682. }
  683.